(library (list-helpers)
  (export flatten
          make-list
          split-off-n
          split-into-n-sized-segments
          split-at
          split-into-segments)
  (import
   (except (rnrs base) let-values map error)
   (only (guile)
         lambda* λ)
   ;; receive form
   (srfi srfi-8))


  (define flatten
    (λ (lst)
      (cond [(null? lst) '()]
            [(pair? lst)
             (append (flatten (car lst))
                     (flatten (cdr lst)))]
            [else
             (list lst)])))


  (define make-list
    (λ (val count)
      (cond
       [(> count 0)
        (cons val (make-list val (- count 1)))]
       [else '()])))


  (define split-off-n
    (λ (lst n)
      (let iter ([lst° lst]
                 [counter 0]
                 [cont
                  (λ (acc-split-off rem-lst)
                    (values acc-split-off rem-lst))])
        (cond
         [(null? lst°)
          (cont '() lst°)]
         [(= counter n)
          (cont '() lst°)]
         [else
          (iter (cdr lst°)
                (+ counter 1)
                (λ (new-tail rem-lst)
                  (cont (cons (car lst°) new-tail)
                        rem-lst)))]))))


  (define split-into-n-sized-segments
    (λ (lst n)
      (cond
       [(null? lst) '()]
       [else
        (receive (split-off-part remaining-list)
            (split-off-n lst n)
          (cons split-off-part
                (split-into-n-sized-segments remaining-list n)))])))


  (define split-at
    (λ (lst pred)
      (let iter ([lst° lst]
                 [cont
                  (λ (acc-split-off rem-lst)
                    (values acc-split-off rem-lst))])
        (cond
         [(null? lst°)
          (cont '() lst°)]
         [(pred (car lst°))
          (cont '() (cdr lst°))]
         [else
          (iter (cdr lst°)
                (λ (new-tail rem-lst)
                  (cont (cons (car lst°) new-tail)
                        rem-lst)))]))))


  (define split-into-segments
    (λ (lst pred)
      (cond
       [(null? lst) '()]
       [else
        (receive (split-off-part remaining-list) (split-at lst pred)
          (cons split-off-part
                (split-into-segments remaining-list pred)))]))))
